/*
 *  lazy.c
 *
 *  Created on: 2010-5-25
 *      Author: liuyond
 */
#include "cpu.h"

int calculate_cf_flag(cpu_t *cpu, int inst, int src, int dst, int ret)
{
	int cf = cpu_get_flag(cpu, CF);

	byte src_byte = src;
	byte dst_byte = dst;
	byte ret_byte = ret;
	word src_word = src;
	word dst_word = dst;
	word ret_word = ret;

	switch (inst)
	{
		case ADD_BYTE:
			cf = (ret_byte < src_byte);
			break;
		case ADD_WORD:
			cf = (ret_word < src_byte);
			break;
		case ADC_BYTE:
			cf = (ret_byte <= src_byte);
			break;
		case ADC_WORD:
			cf = (ret_word <= src_byte);
			break;
		case SBB_BYTE:
			cf = (src_byte < ret_byte) || (dst_byte == 0xFF);
			break;
		case SBB_WORD:
			cf = (src_word < ret_word) || (dst_word == 0xFFFF);
			break;
		case SUB_BYTE:
		case CMP_BYTE:
			cf = (src_byte < dst_byte);
			break;
		case SUB_WORD:
		case CMP_WORD:
			cf = (src_word < dst_word);
			break;
		case NEG_BYTE:
			cf = (ret_byte != 0);
			break;
		case NEG_WORD:
			cf = (ret_word != 0);
			break;
		case LOG_BYTE:
		case LOG_WORD:
			cf = 0;
			break;
	}
	return cf;
}

#define GET_ADD_OVERFLOW(src, dst, result, mask) \
  (((~((src) ^ (dst)) & ((dst) ^ (result))) & (mask)) != 0)

#define GET_SUB_OVERFLOW(src, dst, result, mask) \
   (((((src) ^ (dst)) & ((src) ^ (result))) & (mask)) != 0)

int calculate_of_flag(cpu_t *cpu, int inst, int src, int dst, int ret)
{
	int of = cpu_get_flag(cpu, OF);

	byte src_byte = src;
	byte dst_byte = dst;
	byte ret_byte = ret;
	word src_word = src;
	word dst_word = dst;
	word ret_word = ret;

	switch (inst)
	{
		case ADD_BYTE:
		case ADC_BYTE:
			of = GET_ADD_OVERFLOW(src_byte, dst_byte, ret_byte, 0x80);
			break;
		case ADD_WORD:
		case ADC_WORD:
			of = GET_ADD_OVERFLOW(src_word, dst_word, ret_word, 0x8000);
			break;
		case SBB_BYTE:
		case SUB_BYTE:
		case CMP_BYTE:
			of = GET_SUB_OVERFLOW(src_word, dst_word, ret_word, 0x80);
			break;
		case SBB_WORD:
		case SUB_WORD:
		case CMP_WORD:
			of = GET_SUB_OVERFLOW(src_word, dst_word, ret_word, 0x8000);
			break;
		case INC_BYTE:
			of = (ret_byte == 0x80);
			break;
		case INC_WORD:
			of = (ret_word == 0x8000);
			break;
		case DEC_BYTE:
			of = (ret_word == 0x7F);
			break;
		case DEC_WORD:
			of = (ret_word == 0x7FFF);
			break;
		case NEG_BYTE:
			of = (ret_byte != 0x80);
			break;
		case NEG_WORD:
			of = (ret_word != 0x8000);
			break;
		case LOG_BYTE:
		case LOG_WORD:
			of = 0;
			break;
	}
	return of;
}

int calculate_sf_flag(cpu_t *cpu, int inst, int src, int dst, int ret)
{
	int sf = cpu_get_flag(cpu, SF);

	byte src_byte = src;
	byte dst_byte = dst;
	byte ret_byte = ret;
	word src_word = src;
	word dst_word = dst;
	word ret_word = ret;

	switch (inst)
	{
		case ADD_BYTE:
		case ADC_BYTE:
		case SBB_BYTE:
		case SUB_BYTE:
		case CMP_BYTE:
		case NEG_BYTE:
		case LOG_BYTE:
		case INC_BYTE:
		case DEC_BYTE:
			sf = (ret_byte >= 0x80);
			break;
		case ADD_WORD:
		case ADC_WORD:
		case SBB_WORD:
		case SUB_WORD:
		case CMP_WORD:
		case NEG_WORD:
		case LOG_WORD:
		case INC_WORD:
		case DEC_WORD:
			sf = (ret_word >= 0x8000);
			break;
	}
	return sf;
}

int calculate_zf_flag(cpu_t *cpu, int inst, int src, int dst, int ret)
{
	int zf = cpu_get_flag(cpu, ZF);

	byte src_byte = src;
	byte dst_byte = dst;
	byte ret_byte = ret;
	word src_word = src;
	word dst_word = dst;
	word ret_word = ret;

	switch (inst)
	{
		case ADD_BYTE:
		case ADC_BYTE:
		case SBB_BYTE:
		case SUB_BYTE:
		case CMP_BYTE:
		case NEG_BYTE:
		case LOG_BYTE:
		case INC_BYTE:
		case DEC_BYTE:
			zf = (ret_byte == 0);
			break;
		case ADD_WORD:
		case ADC_WORD:
		case SBB_WORD:
		case SUB_WORD:
		case CMP_WORD:
		case NEG_WORD:
		case LOG_WORD:
		case INC_WORD:
		case DEC_WORD:
			zf = (ret_word == 0);
			break;
	}
	return zf;
}
